// 接口初探
function printLabel (labelObj: {label: string}) {
  console.log(labelObj.label)
}
let myObj = {size: 10, label: 'size 10 Object'}
printLabel(myObj) // size 10 Object


// interface重写以上结构
interface labelObj{
  label: string
}
function printLabel2 (labelObj: labelObj) {
  console.log(labelObj.label)
}
printLabel2(myObj) // size 10 Object
// printLabel2({size: 10, label: 'size 10 Object'}) 
// 上面这种的会被检查器检查Size不存在于接口中,即额外的属性检查

// 可选属性
interface SquareConfig {
  color?: string
  with?: number
}
function creatSquare (config: SquareConfig): {color: string; area: number} {
  let newSquare = {color: 'white', area: 100}
  if (config.color) {
    newSquare.color = config.color
  }
  if (config.with) {
    newSquare.area = config.with * config.with
  }
  return newSquare
}
let mySquare = creatSquare({color: 'black'})
console.log('mySquare', mySquare) // mySquare { color: 'black', area: 100 }

// 只读属性
interface Point {
  readonly x: number
  readonly y: number
}
// 创建一个只读的变量
let point: Point = {x: 3, y: 5}
// ReadonlyArray<Type>类型，它与Array<Type>相似，只是把所有可变方法去掉了，因此可以确保数组创建后再也不能被修改
let ro: ReadonlyArray<string> = ['lee', 'mmonkey']
console.log('ro', ro) // ro [ 'lee', 'mmonkey' ]
let a: string[] = ['1', '2', '3']
// 只读类型,对以标记类型重新赋值也不行,但是可以通过类型断言来重写,但是重写要保证类型一样
// a = ro
a = ro as string[];
console.log(a) // [ 'lee', 'mmonkey' ]

// 额外属性检查
interface SquareConfig1 {
  color?: string
  with?: number
}
function creatSquare1 (SquareConfig1: SquareConfig1): {color: string, with: number} {
  return {color: '1', with: 23}
}
// 这次直接将对象字面量形式的带入  将color属性服役写错为colour 这时候编译报错  
creatSquare1({colour: '1', with: 1})

// 绕开额外属性检查的方式1.类型断言

creatSquare1({colour: '1', with: 1} as SquareConfig1)

// 绕开额外属性检查的方式2  增加字符串索引签名 前提是你能够确定这个对象可能具有某些做为特殊用途使用的额外属性
interface SquareConfig1 {
  color?: string
  with?: number
  [propName: string]: any
}
// 绕开额外属性检查方式3 不带入字面量对象.将对象赋值给另一个变量,然后再带入函数
let obj2 = {colour: '1', with: 1}
creatSquare1(obj2)

// 函数类型
interface SearchFunc {
  (source: string, subString: string) : boolean
}
let mySearch : SearchFunc = function (a: string, b: string) : boolean {
  let result = a.search(b)
  return result > -1
}

// 可索引类型
interface StringArray {
  [index: number] : string
}
let myArray : StringArray = ['Bob', 'Fred']
let myStr : string = myArray[1]

// 数字索引返回的值必须是字符串索引返回值的子类型
class Animal {
  name: string
}
class Dog extends Animal {
  breed: string
}
interface NotOkay {
  [index: number] : Dog
  [index: string]: Animal
}

// 如果可索引类型的结构值，不符合可索引类型的的返回值，检查器将会报错
interface ReadonlyStringArray {
  [index: string]: number
  length: number
  // name: string // 检查器将在这里报错
}
// 将索引签名设置为只读，这样就防止了给索引赋值
interface ReadonlyStringArray1 {
  readonly [index: number]: string
}
let myArray1 : ReadonlyStringArray1 = ['Bob', 'Alice']
// myArray1[3] = 'Mallory' // 报错

// 类类型
interface ClockInterface {
  currentTime: Date
  setTime (d: Date)
}
class Clock implements ClockInterface {
  currentTime: Date
  setTime (d: Date) {
    this.currentTime = d
  }
}
// 继承接口 继承多个接口
interface Shape {
  color: string
}
interface PenStroke {
  penWidth: number
}
interface Square extends Shape, PenStroke {
  sideLength: number
}
let square = <Square>{}
square.color = 'blue'
square.sideLength = 10
square.penWidth = 5.0
